#! /bin/bash -E

# CVE-2023-38408: Remote Code Execution in OpenSSH's forwarded ssh-agent
# ./step3.sh /tmp/step2*
# Copyright (C) 2023 Qualys, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

trap 'echo "$LINENO"; exit 1' ERR || exit "$LINENO"
[ "$#" -eq 1 ]
in="$1"
[ "${in#/}" != "$in" ]
[ -d "$in" ]

out="$(mktemp -d /tmp/step3.XXXXXXXXXX)"
echo "$out"
cd "$out"

grep -rl '^+.*rwx.*\[stack\]' "$in" | sed 's:^.*/\([^/]*\)/maps$:\1:' > 'xstack.maps'
! grep -q '/' 'xstack.maps'

grep -rl '^+[0-9]' "$in" | sed 's:^.*/\([^/]*\)/maps$:\1:' > 'change.maps'
! grep -q '/' 'change.maps'

declare -a signals
while read signum sigspec; do
    [ -z "${signals[signum]}" ]
    signals[signum]="$sigspec"
done <<< "$(kill -l | sed 's/[[:space:]]*\([[:digit:]]*\)[)][[:space:]]*\([^[:space:]]*\)[[:space:]]*/\1 \2\n/g' | grep -v ' SIGRTM' | grep .)"
[ "${signals[11]}" = 'SIGSEGV' ]

while read dir sigmask; do
    dir="${dir%/*}"
    [ -d "$dir" ]
    lib="${dir##*/}"
    sigmask="0x$sigmask"
    for ((signum=1; signum<=64; signum++)); do
        [ "$((sigmask&(1<<(signum-1))))" -ne 0 ] || continue
        sigspec="${signals[signum]}"
        [ -n "$sigspec" ] || continue
        handlers="$(grep -F "sigaction($sigspec, {sa_handler=0x" "$dir/strace" | sed 's/.*sigaction[^=]*=\(0x[[:xdigit:]]*\).*/\1/g')"
        [ -n "$handlers" ]
        for handler in $handlers; do
            addr_size=''
            while read size addr; do
                [ "$((handler))" -ge "$((addr))" ] || continue
                [ "$((handler))" -lt "$((addr+size))" ] || continue
                [ -z "$addr_size" ]
                addr_size="$addr, $size"
            done <<< "$(grep 'mmap[(]NULL, [[:digit:]]*, [^[:space:]]*, [^[:space:]]*, [[:digit:]]*, 0[)] = 0x[[:xdigit:]]*$' "$dir/strace" | awk '{print $3$9}' | tr , ' ')"
            [ -n "$addr_size" ]
            grep -q "munmap[(]$addr_size[^[:digit:]]" "$dir/strace" || continue
            [ -d "$sigspec" ] || mkdir "$sigspec"
            echo "$lib" >> "$sigspec/catch"
            break
        done
    done
done <<< "$(grep -r '^[+]SigCgt:[[:space:]]' "$in")"

for sigspec in SIG*; do
    [ -s "$sigspec/catch" ]
    [ ! -e "$sigspec/raise" ]
    grep -rlF "+++ killed by $sigspec +++"$'\n'"--- $sigspec {" "$in" | sed 's:^.*/\([^/]*\)/strace$:\1:' > "$sigspec/raise"
done

echo done.

